﻿using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Jinndev.Localization {

    public static class LocalizationManager {

        public static SystemLanguage CurrentLanguage { get; private set; }

        private static ILocalizableStorage localizableStorage;
        private static List<ILocalizationLoader> loaders = new List<ILocalizationLoader>();
        private static HashSet<ILocalizable> localizables = new HashSet<ILocalizable>();

        public static void Init(ILocalizableStorage localizableStorage, params ILocalizationLoader[] loaders) {
            LocalizationManager.localizableStorage = localizableStorage;

            if (loaders != null) {
                foreach (ILocalizationLoader loader in loaders) {
                    AddLoader(loader);
                }
            }
        }

        public static void Init(SystemLanguage language, ILocalizableStorage localizableStorage, params ILocalizationLoader[] loaders) {
            Init(localizableStorage, loaders);
            Reload(language);
        }

        public static void AddLoader(ILocalizationLoader loader) {
            if (!loaders.Contains(loader)) {
                loaders.Add(loader);
            }
        }

        public static bool RemoveLoader(ILocalizationLoader loader) {
            return loaders.Remove(loader);
        }

        public static void Reload(SystemLanguage language, bool throwIfException = true) {
            CurrentLanguage = language;
            if (localizableStorage == null) {
                if (throwIfException) {
                    throw new InvalidOperationException("LocalizableStorage not set.");
                }
                else {
                    Debug.LogError("LocalizableStorage not set.");
                }
                return;
            }

            foreach (ILocalizationLoader loader in loaders) {
                try {
                    Dictionary<string, string> dict = loader.Load(language);
                    foreach (KeyValuePair<string, string> pair in dict) {
                        localizableStorage.Set(pair.Key, pair.Value);
                    }
                }
                catch (Exception e) {
                    if (throwIfException) {
                        throw e;
                    }
                    else {
                        Debug.LogException(e);
                    }
                }
            }
        }

        public static string Get(string key, bool returnKeyIfNotFound = true) {
            if (localizableStorage != null) {
                return localizableStorage.Get(key, returnKeyIfNotFound);
            }
            return returnKeyIfNotFound ? key : null;
        }

        public static IEnumerable<string> Get(IEnumerable<string> keys, bool returnKeyIfNotFound = true) {
            List<string> result = new List<string>();
            foreach (string key in keys) {
                result.Add(Get(key, returnKeyIfNotFound));
            }
            return result;
        }

        public static string Format(string key, params object[] args) {
            if (localizableStorage != null) {
                string text = localizableStorage.Get(key, false);
                if (!string.IsNullOrEmpty(text)) {
                    try {
                        return string.Format(text, args);
                    }
                    catch (Exception e) {
                        Debug.LogException(e);
                    }
                }
            }
            return key;
        }

        public static void Set(string key, string text) {
            if (localizableStorage != null) {
                localizableStorage.Set(key, text);
            }
        }

        public static void RegisterLocalizable(ILocalizable localizable) {
            localizables.Add(localizable);
        }

        public static void UnregisterLocalizable(ILocalizable localizable) {
            if (!CommonUtil.IsQuitting) {
                localizables.Remove(localizable);
            }
        }

        public static void ClearLocalizables() {
            localizables.Clear();
        }

        public static void RefreshLocalizables() {
            foreach (ILocalizable localizable in localizables) {
                try {
                    localizable.RefreshText();
                }
                catch (Exception e) {
                    Debug.LogException(e);
                }
            }
        }

        public static void Dispose() {
            CurrentLanguage = SystemLanguage.Unknown;
            if (localizableStorage != null) {
                localizableStorage.Clear();
            }
            loaders.Clear();
            localizables.Clear();
        }

    }

}
